﻿namespace AddressBook.Business.Event
{
	#region "Using Statements"
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;

	using Csla;
	using Csla.Data;
	using Csla.Validation;

	using Business.Person;
	#endregion

	[Serializable]
	public class Location : BusinessBase<Location>
	{
		#region "Business Methods"

		#region "Private Static Member Variables"

		private static PropertyInfo<Int32> IdProperty = RegisterProperty<Int32>(f => f.Id);
		private static PropertyInfo<String> NameProperty = RegisterProperty<String>(f => f.Name);
		private static PropertyInfo<SmartDate> ModifiedDateProperty = RegisterProperty<SmartDate>(f => f.ModifiedDate);
		private static PropertyInfo<LocationAddress> LocationAddressProperty = RegisterProperty<LocationAddress>(f => f.Address);

		#endregion

		#region "Public Properties"

		public Int32 Id
		{
			get { return GetProperty(IdProperty); }
			internal set { LoadProperty(IdProperty, value); }
		}

		public String Name
		{
			get { return GetProperty(NameProperty); }
			set { SetProperty(NameProperty, value); }
		}

		public LocationAddress Address
		{
			get
			{
				if (!(FieldManager.FieldExists(LocationAddressProperty)))
				{
					LoadProperty(LocationAddressProperty, LocationAddress.NewAddress());
				}

				return GetProperty(LocationAddressProperty);
			}
		}

		public string ModifiedDate
		{
			get { return GetProperty(ModifiedDateProperty).ToString(); }
		}

		#endregion

		#endregion

		#region  "Factory Methods"

		public static Location NewLocation()
    {
      return DataPortal.Create<Location>();
    }

		public static Location NewLocation(String name, String address1, String address2, String city, Int32 stateProvinceId, String postalCode)
    {
      return DataPortal.Create<Location>(new LocationAddressCriteria(name, address1, address2, city, stateProvinceId, postalCode));
    }

		public static Location GetLocation(Int32 id)
    {
      return DataPortal.Fetch<Location>(new SingleCriteria<Location, Int32>(id));
    }

		public static void DeleteLocation(Int32 id)
    {
      DataPortal.Delete(new SingleCriteria<Location, Int32>(id));
    }

		private Location()
    { /* require use of factory methods */ }

		#endregion

		#region "Data Access"

		#region "Internal LocationAddressCriteria Class"

		internal class LocationAddressCriteria
		{
			public string Name;
			public String Address1;
			public String Address2;
			public String City;
			public Int32 StateProvinceId;
			public String PostalCode;

			public LocationAddressCriteria(String name, String address1, String address2, String city, Int32 stateProvinceId, String postalCode)
			{
				this.Name = name;
				this.Address1 = address1;
				this.Address2 = address2;
				this.City = city;
				this.StateProvinceId = stateProvinceId;
				this.PostalCode = postalCode;
			}
		}

		#endregion

		[RunLocal()]
		protected override void DataPortal_Create()
		{
			using (BypassPropertyChecks)
			{
				ValidationRules.CheckRules();
			}
		}

		[RunLocal()]
		private void DataPortal_Create(LocationAddressCriteria criteria)
		{
			using (BypassPropertyChecks)
			{
				this.Name = criteria.Name;

				Address.Address1 = criteria.Address1;
				Address.Address2 = criteria.Address2;
				Address.City = criteria.City;
				Address.StateProvinceId = criteria.StateProvinceId;
				Address.PostalCode = criteria.PostalCode;
			}
		}

		private void DataPortal_Fetch(SingleCriteria<Location, Int32> criteria)
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				// get contact data
				AddressBook.Business.Model.Location Location = ctx.DataContext.Locations.First(l => l.Id == criteria.Value);

				using (BypassPropertyChecks)
				{
					this.Id = Location.Id;
					this.Name = Location.Name;

					LoadProperty(ModifiedDateProperty, Location.ModifiedDate);

					// get child data
					LoadProperty(LocationAddressProperty,
											 LocationAddress.GetAddress(Location.Address));
				}
			}
		}

		[Transactional(TransactionalTypes.TransactionScope)]
		protected override void DataPortal_Insert()
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				// insert contact data
				using (BypassPropertyChecks)
				{
					AddressBook.Business.Model.Location location = new AddressBook.Business.Model.Location();

					this.Address.AddressId = Person.Address.AddAddress(this.Address.Address1,
																														 this.Address.Address2,
																														 this.Address.City,
																														 this.Address.StateProvinceId,
																														 this.Address.PostalCode);

					location.Name = this.Name;
					location.AddressId = this.Address.AddressId;
					location.ModifiedDate = System.DateTime.Now;

					ctx.DataContext.Locations.InsertOnSubmit(location);
					ctx.DataContext.SubmitChanges();

					this.Id = location.Id;
				}

				// update child objects
				FieldManager.UpdateChildren(this);
			}
		}

		[Transactional(TransactionalTypes.TransactionScope)]
		protected override void DataPortal_Update()
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				AddressBook.Business.Model.Location location = ctx.DataContext.Locations.First(l => l.Id == this.Id);

				// update location data
				using (BypassPropertyChecks)
				{
					location.Name = this.Name;
					location.ModifiedDate = System.DateTime.Now;

					ctx.DataContext.SubmitChanges();
				}

				// update child objects
				FieldManager.UpdateChildren(this);
			}
		}

		[Transactional(TransactionalTypes.TransactionScope)]
		protected override void DataPortal_DeleteSelf()
		{
			DataPortal_Delete(new SingleCriteria<Location, Int32>(this.Id));
		}

		[Transactional(TransactionalTypes.TransactionScope)]
		private void DataPortal_Delete(SingleCriteria<Location, Int32> criteria)
		{
      using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
      {
        // get location data
        AddressBook.Business.Model.Location location = ctx.DataContext.Locations.First(l => l.Id == criteria.Value);
        int addressId = location.AddressId;

        // delete location data
        ctx.DataContext.Locations.DeleteOnSubmit(location);
        ctx.DataContext.SubmitChanges();

        Person.Address.RemoveAddress(addressId);

        // reset child list field
        LoadProperty(LocationAddressProperty, LocationAddress.NewAddress());
      }
		}

		#endregion
	}
}